package net.yegong;

import java.io.IOException;
import java.io.ObjectOutputStream;

import net.yegong.matrix.Matrix;
import net.yegong.matrix.MatrixHelper;
import net.yegong.matrix.RowVector;
import net.yegong.matrix.Transformer;
import net.yegong.mva.ComputingException;
import net.yegong.mva.pca.PCACalc;
import net.yegong.mva.pca.PCACalcFactory;
import net.yegong.mva.pca.PCAResult;

public class Zip {

	public static void zip(Reader reader, ObjectOutputStream os, float error) throws IOException, ComputingException {
		Matrix m;
		int bands = reader.getBands();
		int rows = reader.getRows();
		int cols = reader.getCols();
		Logger.log("Bands: %d\nRows: %d\nCols: %d", bands, rows, cols);
		os.writeInt(bands);
		os.writeInt(rows);
		os.writeInt(cols);
		while (null != (m = reader.getNext())) {
			PCACalc pca = PCACalcFactory.createPCACalc("PCA");
			PCAResult result = pca.calculate(m.clone(), -1, true, error, MatrixHelper.eps());

			Matrix eig = result.getEigenVector();
			RowVector std = result.getStdev();
			RowVector mean = result.getMean();
			int factor = eig.getColumnsCount();

			// ------------------------------------------------------ //
			// output header //
			// ------------------------------------------------------ //

			os.writeInt(factor);
			for (int i = 0; i < eig.getRowsCount(); ++i) {
				for (int j = 0; j < eig.getColumnsCount(); ++j) {
					os.writeFloat(eig.get(i, j));
				}
			}
			for (int i = 0; i < bands; ++i) {
				os.writeFloat(std.get(i));
			}
			for (int i = 0; i < bands; ++i) {
				os.writeFloat(mean.get(i));
			}

			// ------------------------------------------------------ //
			// output zipped data //
			// ------------------------------------------------------ //

			Transformer.minusEachRow(m, result.getMean());
			Transformer.divideEachRow(m, result.getStdev());
			Matrix a1 = m.leftMultiply(result.getEigenVector());

			RowVector max = a1.maxOfColumn();
			RowVector min = a1.minOfColumn();
			Transformer.minusEachRow(a1, min);
			Transformer.divideEachRow(a1, max.minus(min).multiply(1.0f / 255).toRowVector());
			for (int i = 0; i < factor; ++i) {
				os.writeFloat(max.get(i));
			}
			for (int i = 0; i < factor; ++i) {
				os.writeFloat(min.get(i));
			}

			int nRows = a1.getRowsCount();
			os.writeInt(nRows);

			for (float f : a1.getColumnMajorArray()) {
				int value = Math.round(f);
				os.write(value);
			}
		}
		os.writeInt(0);
		os.flush();
	}

}
